//
//  BookDBManager.m
//  readNovels
//
//  Created by wulanzhou on 2017/2/27.
//  Copyright © 2017年 wulanzhou. All rights reserved.
//

#import "SQLDBManager.h"
#import <FMDB/FMDB.h>
#import <MJExtension/MJExtension.h>

@interface SQLDBManager ()
@property(nonatomic,strong) FMDatabaseQueue *userDBQueue;
@end

@implementation SQLDBManager

+ (SQLDBManager *)shareInstance
{
    static dispatch_once_t  onceToken;
    static SQLDBManager * sSharedInstance;
    
    dispatch_once(&onceToken, ^{
        sSharedInstance = [[SQLDBManager alloc] init];
    });
    return sSharedInstance;
}

#pragma mark -创建数据库


/**
 创建数据库(数据库存放在document/db/路径下)
 
 @param name 数据库名称
 @return 成功YES,否则为NO
 */
- (BOOL)createDBWithName:(NSString *)name{
    
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *doc = [paths objectAtIndex:0];
    return [self createDBWithPath:[doc stringByAppendingPathComponent:@"db"] dbName:name sqlTables:nil];
}

/**
 创建数据库(数据库存放在document/db/路径下)
 
 @param name 数据库名称
 @param sqlArray 创建表的sql
 @return 成功YES,否则为NO
 */
- (BOOL)createDBWithName:(NSString *)name sqlTables:(NSArray *)sqlArray{

    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *doc = [paths objectAtIndex:0];
    return [self createDBWithPath:[doc stringByAppendingPathComponent:@"db"] dbName:name sqlTables:sqlArray];
}

/**
 创建数据库
 
 @param path 数据库路径
 @param name 数据库名称
 @param sqlArray 创建表的sql
 @return 成功YES,否则为NO
 */
- (BOOL)createDBWithPath:(NSString *)path dbName:(NSString *)name sqlTables:(NSArray *)sqlArray{

    @synchronized(self.userDBQueue){
        
        if (0 == [path length] || 0 == [name length] || [sqlArray count] == 0)
        {
            NSLog(@"数据库路径或数据库名称或sql为空");
            [self.userDBQueue close];
            self.userDBQueue = nil;
            return NO;
        }
        //创建目录
        [self createDirectoryWithPath:path];
        NSString *filePath = [path stringByAppendingPathComponent:name];
        
        self.userDBQueue = [FMDatabaseQueue databaseQueueWithPath:filePath];
        if (self.userDBQueue)
        {
            
            if(sqlArray && [sqlArray count] >0){
                
                __block BOOL flag = NO;
                [self.userDBQueue inTransaction:^(FMDatabase *db, BOOL *rollback) {
                    
                    for (NSString *sqlStr in sqlArray)
                    {
                        flag = [db executeUpdate:sqlStr];
                        if (!flag)
                        {
                            *rollback = YES;
                            break;
                        }
                    }
                }];
                
                if (!flag)
                {
                    NSLog(@"数据库创建表失败");
                }else{
                    NSLog(@"数据库创建表成功");
                }
                
                return flag;
           }
            
            NSLog(@"初始化数据库成功");
            return YES;
           
        }
        else
        {
            NSLog(@"用数据库创建失败");
        }
    }
    return NO;
    
}


#pragma mark -执行创建、删除、新增、更新数据库操作
/**
 执行创建、删除、新增、更新数据库操作
 
 @param sql sql语句
 @return 成功YES,否则为NO
 */
- (BOOL)update:(NSString *)sql, ...NS_REQUIRES_NIL_TERMINATION{

    @synchronized(self.userDBQueue){
    
        if (!self.userDBQueue || 0 == [sql length])
        {
            return NO;
        }
        
        if (!sql) {
            return NO;
        }

        
        //首先在函数里定义一个va_list型的变量,这里是p_list,这个变量是指向参数的指针.
        va_list args;
        //然后用va_start宏初始化变量p_list.
        va_start(args, sql);
        
        BOOL flag = [self update:sql withVAList:args];
        //清空参数指针，最后用va_end宏结束可变参数的获取。
        va_end(args);
        
        return flag;
    }

}

/**
 执行创建、删除、新增、更新数据库事物操作
 
 @param sqlArray sql语句
 @param args sql参数值
 @return 成功YES,否则为NO
 */
- (BOOL)transactionUpdate:(NSArray *)sqlArray arguments:(NSArray *)args{


    @synchronized(self.userDBQueue)
    {
        if (!self.userDBQueue || 0 == [sqlArray count])
        {
            return NO;
        }
        
        __block BOOL flag = NO;
        
        [self.userDBQueue inTransaction:^(FMDatabase *db, BOOL *rollback) {
            NSInteger index = 0;
            for (NSString *sqlStr in sqlArray)
            {
                if (args && [args count] > 0 && index < [args count]) {
                    flag = [db executeUpdate:sqlStr withArgumentsInArray:args[index]];
                }else{
                    flag = [db executeUpdate:sqlStr];
                }
                if (!flag)
                {
                    //NSLog(@" sqlStr =%@ ,args = %@",sqlStr,args[index]);
                    *rollback = YES;
                    break;
                }
                
                index ++;
            }
        }];
        
        return flag;
    }
}

#pragma mark -查询
/**
 查询
 
 @param cls 转化的model
 @param sql 查询语句
 @return 返回查询集合
 */
- (NSArray *)queryModels:(Class)cls sql: (NSString *)sql, ...NS_REQUIRES_NIL_TERMINATION{

    //首先在函数里定义一个va_list型的变量,这里是p_list,这个变量是指向参数的指针.
    va_list p_list;
    //然后用va_start宏初始化变量p_list.
    va_start(p_list, sql);
    
    NSArray *rowDicArray = [self query:sql withVAList:p_list];
    
    //清空参数指针，最后用va_end宏结束可变参数的获取。
    va_end(p_list);
    
    if (rowDicArray && [rowDicArray count]>0) {
        NSMutableArray *resultM = [NSMutableArray array];
        for (NSDictionary *rowDic in rowDicArray) {
            id model = [cls mj_objectWithKeyValues:rowDic];
            [resultM addObject:model];
        }
        
        return resultM;
    }
    return nil;
}

/**
 查询
 
 @param sql 查询语句
 @return 返回查询集合
 */
- (NSArray *)query:(NSString *)sql, ...NS_REQUIRES_NIL_TERMINATION;
{
    //首先在函数里定义一个va_list型的变量,这里是p_list,这个变量是指向参数的指针.
    va_list p_list;
    //然后用va_start宏初始化变量p_list.
    va_start(p_list, sql);
    
    NSArray *source = [self query:sql withVAList:p_list];
    
    //清空参数指针，最后用va_end宏结束可变参数的获取。
    va_end(p_list);
    return source;
}



#pragma mark -私有方法
- (BOOL)update:(NSString *)sql withVAList:(va_list)args{
    
    __block BOOL flag = NO;
    
    [self.userDBQueue inDatabase:^(FMDatabase *db) {
        flag = [db executeUpdate:sql withVAList:args];
    }];
    
    return flag;
}
- (NSArray *)query:(NSString *)sql withVAList:(va_list)args{
    @synchronized(self.userDBQueue)
    {
        if (!self.userDBQueue)
        {
            return nil;
        }
        if (!sql) {
            return nil;
        }
        
        __block NSMutableArray *aList = [[NSMutableArray alloc] initWithCapacity:2];
        [self.userDBQueue inDatabase:^(FMDatabase *db) {
            FMResultSet *result = [db executeQuery:sql withVAList:args];
            if (result)
            {
                while ([result next])
                {
                    NSMutableDictionary  *aDict = [[NSMutableDictionary alloc] initWithCapacity:2];
                    NSArray *keyList = [[result columnNameToIndexMap] allKeys];
                    for (NSString *aKey in keyList)
                    {
                        id obj = [result objectForColumnName:aKey];
                        [aDict setObject:obj forKey:aKey];
                    }
                    [aList addObject:aDict];
                }
                [result close];
            }
            
        }];
        return aList;
        
    }
    
}
/**
 *  在指定的文件路径中创建文件夹
 *  @param path     文件路径
 *  @return         创建是否成功
 */
- (BOOL)createDirectoryWithPath:(NSString*)path{
    BOOL success=YES;
    BOOL isDir = NO;
    NSFileManager *fileManager = [NSFileManager defaultManager];
    BOOL existed = [fileManager fileExistsAtPath:path isDirectory:&isDir];
    if (!(isDir == YES && existed == YES) )
    {
        success=[fileManager createDirectoryAtPath:path withIntermediateDirectories:YES attributes:nil error:nil];
    }
    return success;
}

@end
